package com.example.web.office_file.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.utils.TypeUtil;
import com.example.web.office_file.entity.OfficeFile;
import com.example.web.office_file.mapper.OfficeFileMapper;
import com.example.web.office_file.service.IOfficeFileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author LS
 * @since 2024-03-05
 */
@Service
public class OfficeFileServiceImpl extends ServiceImpl<OfficeFileMapper, OfficeFile> implements IOfficeFileService {

    @Autowired
    private OfficeFileMapper officeFileMapper;
    @Value("${file.upload.path}")
    private String fileRootPath;


    //查询文件
    public Page<OfficeFile> getFileByPage(Integer currentPage, Integer pageSize, String curDir, Integer op) {
        LambdaQueryWrapper<OfficeFile> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        //文件
        if (op == 1) {
            String location = fileRootPath + curDir;
            if (!curDir.equals("/")) {
                location += "/";
            }
            lambdaQueryWrapper.eq(OfficeFile::getCurDir, location)
                    .eq(OfficeFile::getIsDeleted, 0)
                    .select(OfficeFile::getId, OfficeFile::getFileName, OfficeFile::getFileType, OfficeFile::getFileSize, OfficeFile::getIsDir, OfficeFile::getCreateTime)
                    .orderByDesc(OfficeFile::getIsDir)
                    .orderByAsc(OfficeFile::getId);
        } else if (op == 2) {//回收站
            LocalDateTime now = LocalDateTime.now();
            lambdaQueryWrapper.eq(OfficeFile::getIsDeleted, 1)
                    .ge(OfficeFile::getExpiredTime, now)
                    .eq(OfficeFile::getIsDir, 0);
        }
        Page<OfficeFile> filePage = new Page<>(currentPage, pageSize);

        officeFileMapper.selectPage(filePage, lambdaQueryWrapper);
        int size = filePage.getRecords().size();
        for (int i = 0; i < size; i++) {
            if (filePage.getRecords().get(i).getIsDir() == 1) {
                Integer id = filePage.getRecords().get(i).getId();
                filePage.getRecords().get(i).setFileSize(countSize(id));
            }
        }
        return filePage;
    }

    //统计某个文件夹的大小
    @Override
    public Long countSize(Integer id) {
        OfficeFile dir = officeFileMapper.selectById(id);
        if (dir == null || dir.getIsDir() == 0) {
            throw new RuntimeException("不存在此目录");
        }
        String dirFileLocation = dir.getFileLocation();
        LambdaQueryWrapper<OfficeFile> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        String replace = dirFileLocation.replace("\\", "\\\\");
        lambdaQueryWrapper.like(OfficeFile::getCurDir, replace)
                .eq(OfficeFile::getIsDeleted, 0);
        List<OfficeFile> fileList = officeFileMapper.selectList(lambdaQueryWrapper);
        Long countSize = 0L;
        for (OfficeFile file : fileList) {
            if (file.getIsDir() == 0) {
                countSize += file.getFileSize();
            }
        }
        return countSize;
    }

    //创建文件夹
    @Override
    public String createDir(Map<String, String> map) {
        String curDir = map.get("curDir");
        String dirName = map.get("dirName");
        if (StringUtils.isBlank(dirName)) {
            return "文件夹名为空！";
        }
        if (dirName.contains("\\") || dirName.contains("/")) {
            return "文件夹中包含斜杠！";
        }
        String location = fileRootPath + curDir;
        if (!curDir.equals("/")) {
            location += "/";
        }
        java.io.File file = new java.io.File(location + dirName);
        if (!file.exists()) {
            OfficeFile dirFile = new OfficeFile();
            dirFile.setFileName(dirName);
            dirFile.setCreateTime(new Date());
            dirFile.setFileType("文件夹");
            dirFile.setCreator(map.get("creator"));
            dirFile.setCurDir(location);
            dirFile.setFileLocation(location + dirName);
            dirFile.setIsDir(1);
            if (file.mkdir()) {
                officeFileMapper.insert(dirFile);
                return "文件夹创建成功！";
            }
        } else {
            LambdaQueryWrapper<OfficeFile> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(OfficeFile::getCurDir, location)
                    .eq(OfficeFile::getFileName, dirName);
            OfficeFile dir = officeFileMapper.selectOne(lambdaQueryWrapper);
            if (dir.getIsDeleted() == 0) {
                return "文件夹已存在！";
            }
            dir.setIsDeleted(0);
            officeFileMapper.updateById(dir);
        }
        return "文件夹创建失败！";
    }


    //文件上传
    @Override
    public Boolean upload(MultipartFile uploadFile, String curDir, String creator) {
        String suf = Objects.requireNonNull(uploadFile.getOriginalFilename()).substring(uploadFile.getOriginalFilename().lastIndexOf("."));
        String newFileName = UUID.randomUUID().toString().replace("-", "") + suf;
        String location = fileRootPath + curDir;
        if (!curDir.equals("/")) {
            location += "/";
        }

        OfficeFile file = new OfficeFile();
        file.setFileName(uploadFile.getOriginalFilename());
        String type = TypeUtil.judgeType(suf);
        file.setFileType(type);
        file.setFileSize(uploadFile.getSize() / 1024);
        file.setCurDir(location);
        file.setFileLocation(location + newFileName);
        file.setFileExtension(suf);
        file.setCreator(creator);
        file.setCreateTime(new Date());
        file.setIsDir(0);//TODO

        System.out.println(location);
        if (realUpload(uploadFile, location, newFileName))
            return officeFileMapper.insert(file) > 0;
        return false;
    }

    /**
     * 真实上传
     *
     * @param uploadFile 上传文件
     */
    public Boolean realUpload(MultipartFile uploadFile, String location, String newFileName) {
        java.io.File file_dir = new java.io.File(location);
        if (!file_dir.exists()) {
            file_dir.mkdir();
        }
        try {
            uploadFile.transferTo(new java.io.File(location + newFileName));
            return true;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 文件下载
     */
    @Override
    public Boolean download(Integer id, HttpServletRequest request, HttpServletResponse response) {
        OfficeFile file = officeFileMapper.selectById(id);
        if (file == null) {
            return false;
        }
        String fileName = file.getFileName();
        FileInputStream fileInputStream;
        try{
            fileInputStream = new FileInputStream(file.getFileLocation());
            response.setContentType(request.getSession().getServletContext().getMimeType(file.getFileExtension()));//获取文件的mimetype
            response.setHeader("content-disposition","attachment;fileName="+ URLEncoder.encode(fileName,"UTF-8"));
            ServletOutputStream os = response.getOutputStream();
            FileCopyUtils.copy(fileInputStream,os);
        }catch (IOException e){
            throw new RuntimeException(e);
        }
        return true;
    }

    /**
     * 根据文件名查询
     */
    public Page<OfficeFile> findByFileNameLike(Integer pageNum,Integer pageSize,String fileName){

        //构建查询条件
        LambdaQueryWrapper<OfficeFile> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(OfficeFile::getFileName,fileName)
                .orderByDesc(OfficeFile::getCreateTime);
        //分页查询
        Page<OfficeFile> page = new Page<>(pageNum,pageSize);
        officeFileMapper.selectPage(page,lambdaQueryWrapper);
        return page;
    }
}
